import java.util.ArrayList;
import java.util.List;

public class Generator {

	private List<Punkt> punkty;

	private double A;

	private double t1;

	// d - czas trwania sygnału
	private double d;

	private double T;

	// kw - współczynnik wypełnienia
	private double kw;

	private int f;

	private double pi = 3.1415926;

	// miejsce skoku jednostkowego
	private double ts;

	private double poss;

	/**
	 * 
	 * @param A
	 *            - amplituda
	 * @param t1
	 *            - początek
	 * @param d
	 *            - czas trwania
	 * @param T
	 *            - okres
	 * @param kw
	 *            - współczynnik wypełnienia
	 * @param f
	 *            - częstotliwość probkowania
	 * @param ts
	 *            - moment skoku amplitudy
	 * @param poss
	 *            - prawdopodobienstwo
	 */
	public void ustawParametrySygnalu(double A, double t1, double d, double T,
			double kw, int f, double ts, double poss) {
		this.A = A;
		this.t1 = t1;
		this.d = d;
		this.T = T;
		this.kw = kw;
		this.f = f;
		this.ts = ts;
		this.poss = poss;
	}

	public void generujSygnalCiagly(String mode, Signal signal) {

		ustawParametry(signal);
		ArrayList<Punkt> points = new ArrayList<Punkt>();
		signal.setPoints(points);
		signal.setCiagly(true);

		int ilosc = (int) (d * f);
		double deltaT = d / ilosc;
		double x = t1;
		for (int i = 0; i < ilosc; i++) {
			Punkt p = new Punkt();
			p.setRealX(x);
			if (mode.trim().equals("sinus")) {
				p.setRealValue(sinus(x));
			}
			if (mode.trim().equals("sinusj")) {
				p.setRealValue(sinusJednopolowkowo(x));
			}
			if (mode.trim().equals("sinusd")) {
				p.setRealValue(sinusdwupolowkowo(x));
			}
			if (mode.trim().equals("prost")) {
				p.setRealValue(prostokatny(x));
			}
			if (mode.trim().equals("prostSym")) {
				p.setRealValue(prostokatnySymetryczny(x));
			}
			if (mode.trim().equals("trojk")) {
				p.setRealValue(trojkatny(x));
			}
			if (mode.trim().equals("skok")) {
				p.setRealValue(skok(x));
			}
			if (mode.trim().equals("szumGaussa")) {
				p.setRealValue(szumGaussa(x));
			}
			if (mode.trim().equals("szumJedn")) {
				p.setRealValue(szumJedn(x));
			}
			x += deltaT;

			points.add(p);
		}

	}

	private void ustawParametry(Signal signal) {
		signal.setA(this.A);
		signal.setD(this.d);
		signal.setF(this.f);
		signal.setT(this.T);
		signal.setT1(this.t1);
	}

	public void generujSygnalDyskretny(String mode, Signal signal) {

		ustawParametry(signal);
		signal.setCiagly(false);

		ArrayList<Punkt> points = new ArrayList<Punkt>();
		signal.setPoints(points);

		int ilosc = (int) (d * f);
		double deltaT = d / ilosc;
		double x = t1;
		for (int i = 0; i < ilosc; i++) {
			Punkt p = new Punkt();
			p.setRealX(x);

			if (mode.trim().equals("impuls")) {
				p.setRealValue(impuls(x));
			}
			if (mode.trim().equals("szum")) {
				p.setRealValue(szumImpulsowy(x));
			}
			x += deltaT;

			points.add(p);
		}

	}

	private double round(double x) {
		double temp = x * 1000000;
		int temp2 = (int) temp;
		return temp2 / 1000000.0;

	}

	private Double impuls(double x) {
		if (round(x) == 0) {
			return A;
		}
		return 0d;
	}

	private Double szumImpulsowy(double x) {
		double p = Math.random();

		if (p <= this.poss) {
			return A;
		} else {
			return 0d;
		}
	}

	private Double szumJedn(double x) {
		return Math.random() * 2 * A - A;
	}

	private Double szumGaussa(double x) {
		return Math.random() * 2 * A - A;
	}

	private Double skok(double x) {
		if (x < ts) {
			return 0d;
		}
		if (x == ts) {
			return A / 2;
		}
		if (x > ts) {
			return A;
		}
		return null;
	}

	private Double trojkatny(double x) {

		for (int k = 0; k < d - t1; k++) {
			if (x >= k * T + t1 && x < kw * T + k * T + t1) {
				return (A / (kw * T)) * (x - k * T - t1);
			} else {
				return (-A / (T * (1 - kw))) * (x - k * T - t1)
						+ (A / (1 - kw));
			}
		}
		return 888888888d;
	}

	private Double prostokatny(double x) {

		for (int k = 0; k < d - t1; k++) {
			if (x >= k * T + t1 && x < kw * T + k * T + t1) {
				return A;
			}
		}

		return 0.0;
	}

	private Double prostokatnySymetryczny(double x) {

		for (int k = 0; k < d - t1; k++) {
			if (x >= k * T + t1 && x < kw * T + k * T + t1) {
				return A;
			}
		}

		return -A;
	}

	public double sinus(double x) {

		double d;
		d = A * Math.sin((2 * pi / T) * (x - t1));
		return d;
	}

	public double sinusJednopolowkowo(double x) {

		double d;
		d = A * Math.sin((2 * pi / T) * (x - t1));
		if (d <= 0) {
			d = 0;
		}

		return d;
	}

	public double sinusdwupolowkowo(double x) {

		double d;
		d = A * Math.sin((2 * pi / T) * (x - t1));
		if (d < 0) {
			d *= -1;
		}

		return d;
	}

	/*
	 * public void generateSinus(int ile, double t1, double b, String tryb,
	 * double A, double T) {
	 * 
	 * punkty = new ArrayList<Punkt>(); double krok = (b-t1)/ile; int j=0;
	 * System.out.println("od " + t1 + " do " + b + " co " + krok); for (double
	 * i=t1; j<ile; i=i+krok, j=j+1) { punkty[j] = new Punkt();
	 * punkty[j].setRealX(i);
	 * 
	 * if (tryb.trim().equals("sinus")) {
	 * 
	 * punkty[j].setRealValue(Math.sin(i)); } else if
	 * (tryb.trim().equals("sinus1")) {
	 * 
	 * punkty[j].setRealValue(Math.sin(i)); if (punkty[j].getRealValue()<=0) {
	 * 
	 * punkty[j].setRealValue(0.0d); } } else if (tryb.trim().equals("sinus2"))
	 * {
	 * 
	 * punkty[j].setRealValue(Math.sin(i)); if (punkty[j].getRealValue()<0) {
	 * 
	 * punkty[j].setRealValue(punkty[j].getRealValue()); } }
	 * 
	 * punkty[j].setRealValue(punkty[j].getRealValue()*A); } }
	 * 
	 * public void generateSquare(int ile, double t1, double b, String tryb,
	 * double A, double T) {
	 * 
	 * size = ile; punkty = new Punkt[ile]; double krok = (b-t1)/ile; int j=0;
	 * 
	 * if (true) {
	 * 
	 * JeĹ›li od t0 do t0+1/2T to A jeĹ›li od t1 do t0+T to 0 lub -A itd.
	 * 
	 * for (double i=t1; j<ile; i=i+krok, j=j+1) {
	 * 
	 * punkty[j].setRealX(i); boolean dodatnie = true;
	 * 
	 * if (i%T)
	 * 
	 * if (dodatnie) { punkty[j].setRealValue(A); } else { if
	 * (tryb.trim().equals("zwykly")) { punkty[j].setRealValue(0d); } else {
	 * punkty[j].setRealValue(-A); } } } } } Parametry: A, ns, n1, l, f gdzie:
	 * n1 - numer pierwszej prĂłbki; ns â€“ numer prĂłbki, dla ktĂłrej
	 * nastÄ™puje skok amplitudy; f â€“ czÄ™stotliwoĹ›Ä‡ prĂłbkowania.
	 *//**
	 * funkcja generujÄ…ca impuls jednostkowy
	 * 
	 * @param f
	 *            - czÄ™stotliwoĹ›Ä‡
	 * @param n1
	 *            - numer pierwszej prĂłbki (na razie nie brane pod uwagÄ™,
	 *            przyjÄ™te ĹĽe 0)
	 * @param ns
	 *            - numer prĂłbki gdzie wystÄ™puje impuls
	 * @param A
	 *            - amplituda
	 * @param l
	 *            - nie wiem co to na razie
	 */
	/*
	 * public void individualImpulse(double f, int n1, int ns, double A, String
	 * l, int numberOfSamples) {
	 * 
	 * punkty = new Punkt[numberOfSamples]; for (int i=n1; i<numberOfSamples;
	 * i++) { punkty[i] = new Punkt(); punkty[i].setRealX(i/f); if (i==ns) {
	 * punkty[i].setRealValue(A); } else { punkty[i].setRealValue(0.0d); } }
	 * 
	 * }
	 *//**
	 * A, t1, d, f, p gdzie p funkcja generujÄ…ca szum impulsowy
	 * 
	 * @param f
	 *            - czÄ™stotliwoĹ›Ä‡
	 * @param n1
	 *            - numer pierwszej prĂłbki (na razie nie brane pod uwagÄ™,
	 *            przyjÄ™te ĹĽe 0)
	 * @param ns
	 *            - numer prĂłbki gdzie wystÄ™puje impuls
	 * @param A
	 *            - amplituda
	 * @param d
	 *            - nie wiem co to na razie
	 */
	/*
	 * public void szumImpulsowy(double f, double t1, int ns, double A, double
	 * d, double p, int numberOfSamples) {
	 * 
	 * punkty = new Punkt[numberOfSamples]; for (int i=0; i<numberOfSamples;
	 * i++) { punkty[i] = new Punkt(); punkty[i].setRealX(t1); //JAK TU KURWA TO
	 * PRAWDOPODOBIEĹ�STWO ZASTOSOWAÄ†? if (true) { punkty[i].setRealValue(A); }
	 * else { punkty[i].setRealValue(0.0d); }
	 * 
	 * t1+=d; }
	 * 
	 * } //A, t1, d. public void szujJednostajny(double A, double t1, double d,
	 * double tk) {
	 * 
	 * }
	 * 
	 * //A, t1, d, ts. public void skokJednostkowy(double t1, double A, double
	 * d, double ts, double tk) {
	 * 
	 * int numberOfSamples =(int) ((tk-t1)/d); punkty = new
	 * Punkt[numberOfSamples];
	 * 
	 * for (int i=0; i<numberOfSamples; i++) { punkty[i] = new Punkt();
	 * punkty[i].setRealX(t1);
	 * 
	 * if (t1<ts) { punkty[i].setRealValue(0.0d); } else if (t1==ts){
	 * punkty[i].setRealValue(A/2); } else { punkty[i].setRealValue(A); }
	 * 
	 * t1+=d; } }
	 */

	public List<Punkt> getPunkty() {
		return punkty;
	}

	public void setPunkty(List<Punkt> punkty) {
		this.punkty = punkty;
	}

	public double getA() {
		return A;
	}

	public void setA(double a) {
		A = a;
	}

	public double getT1() {
		return t1;
	}

	public void setT1(double t1) {
		this.t1 = t1;
	}

	public double getD() {
		return d;
	}

	public void setD(double d) {
		this.d = d;
	}

	public double getT() {
		return T;
	}

	public void setT(double t) {
		T = t;
	}

	public double getKw() {
		return kw;
	}

	public void setKw(double kw) {
		this.kw = kw;
	}

	public int getF() {
		return f;
	}

	public void setF(int f) {
		this.f = f;
	}

	public double getPi() {
		return pi;
	}

	public void setPi(double pi) {
		this.pi = pi;
	}

}
